/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package phd.dupenois.changeidentifiers.application.graphical.frames;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;
import phd.dupenois.changeidentifiers.dotpatterns.Dot;
import phd.dupenois.changeidentifiers.dotpatterns.DotPattern;
import phd.dupenois.changeidentifiers.footprints.Footprint;
import uk.co.dupenois.geometry.Coordinate;

/**
 *
 * @author Max
 */
public class Grid extends JPanel implements MouseListener, MouseMotionListener, ComponentListener{
    private static Color COLOUR_FOOTPRINT_BORDER = Color.BLUE;
    private static Color COLOUR_FOOTPRINT_FILL = new Color(0, 0, 200, 100);
    private static Color COLOUR_DOT = Color.RED;
    private static Color COLOUR_GRID = Color.GRAY;
    private static Color COLOUR_ORIGIN = Color.BLACK;


    private int gridSpacing;
    private DotPattern dotPattern;
    private GridListener listener;
//    private FootprintPanel footprintPanel;
    private Footprint footprint;
    private Point bottomLeft;
    private boolean mouseIn;
    private Point dragStart;
    private Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
    private Cursor dragCursor = new Cursor(Cursor.MOVE_CURSOR);

    private Container container;


    public Grid(GridListener listener, Container container){
        this(listener, container, 5);
    }
    public Grid(GridListener listener, Container container, int gridSpacing){
        super();
        this.container = container;
//        this.setBackground(Color.WHITE);
        this.gridSpacing = gridSpacing;
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.addComponentListener(this);
        this.listener = listener;
//        footprintPanel = new FootprintPanel(Color.BLUE, this);
//        this.add(footprintPanel);
//        this.footprintPanel.setBounds(0, 0, this.getDimensions().width, this.getDimensions().height);
        this.bottomLeft = new Point(0, 0);
        this.setDoubleBuffered(true);
    }

    public void setDotPattern(DotPattern dotPattern){
        this.dotPattern = dotPattern;
        this.repaint();
    }
    public void setFootprint(Footprint footprint){
//        this.footprintPanel.setFootprint(footprint);
        this.footprint = footprint;
        this.repaint();
    }

    private Polygon convertFootprintToPolygon(Footprint footprint){
        Coordinate[] coords = footprint.getCoordinates();
        Polygon polygon = new Polygon();
        Point point;
        for(Coordinate c : coords){
            point = getScreenPosition(c);
            polygon.addPoint(point.x, point.y);
        }
        return polygon;
    }




    @Override
    public void paint(Graphics g){
        Graphics2D g2 = (Graphics2D)g;
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, this.getDimensions().width, this.getDimensions().height);
        //Vertical Lines
        for(int i = bottomLeft.x; i < this.getBottomRight().x; i++){
            if(i!=0&&i%gridSpacing!=0)continue;
            if(i==0){
                g2.setColor(COLOUR_ORIGIN);
                g2.setStroke(new BasicStroke(3));
            }else{
                g2.setColor(COLOUR_GRID);
                g2.setStroke(new BasicStroke(1));
            }
            Point screenLineStart = getScreenPosition(new Point(i, bottomLeft.y));
            Point screenLineFinish = getScreenPosition(new Point(i, getTopLeft().y));
            g2.drawLine(screenLineStart.x, 0, screenLineFinish.x, this.getDimensions().height-1);
        }
        //Horizontal Lines
        for(int i = bottomLeft.y; i < this.getTopLeft().y; i++){
            if(i!=0&&i%gridSpacing!=0)continue;
            if(i==0){
                g2.setColor(COLOUR_ORIGIN);
                g2.setStroke(new BasicStroke(3));
            }else{
                g2.setColor(COLOUR_GRID);
                g2.setStroke(new BasicStroke(1));
            }
            Point screenLineStart = getScreenPosition(new Point(bottomLeft.x, i));
            Point screenLineFinish = getScreenPosition(new Point(getBottomRight().x, i));
            g2.drawLine(0, screenLineStart.y, this.getDimensions().width-1, screenLineFinish.y);
    
        }

        g2.setColor(COLOUR_DOT);
        if(dotPattern!=null){
            Dot[] dots = dotPattern.getDots();
            for(Dot d : dots){
                Point screenLoc = getScreenPosition(d);
                g2.fillOval(screenLoc.x-5, screenLoc.y-5, 10, 10);
            }
//            System.out.println("Shown dots "+dots.length);
        }

        if(this.footprint!=null && footprint.getLines().length>3){
            Polygon footprintPolygon = convertFootprintToPolygon(footprint);

            g2.setColor(COLOUR_FOOTPRINT_BORDER);
            g2.drawPolygon(footprintPolygon);
            g2.setColor(COLOUR_FOOTPRINT_FILL);
            g2.fillPolygon(footprintPolygon);
        }

//        this.footprintPanel.paint(g);
//        this.footprintPanel.repaint();
    }


    public Point getBottomRight(){
        return new Point(bottomLeft.x+this.getDimensions().width, bottomLeft.y);
    }
    public Point getTopRight(){
        return new Point(bottomLeft.x+this.getDimensions().width, bottomLeft.y+this.getDimensions().height);

    }
    public Point getTopLeft(){
        return new Point(bottomLeft.x, bottomLeft.y+this.getDimensions().height);

    }
    public Point getScreenPosition(Coordinate coord){
        Point point = coordinateToPoint(coord);
        return getScreenPosition(point);
    }
    public Point getScreenPosition(Point point){
        return new Point(point.x-this.bottomLeft.x, this.getDimensions().height-(point.y-this.bottomLeft.y));
    }
    public Point getRealFromScreen(Point point){

        return new Point(this.bottomLeft.x+point.x, (this.getDimensions().height-point.y)+this.bottomLeft.y);
    }
    public static Point coordinateToPoint(Coordinate coord){
        int x = (int)Math.round(coord.getX());
        int y = (int)Math.round(coord.getY());
        return new Point(x, y);
    }

    public void mouseClicked(MouseEvent arg0) {
    }

    public void mousePressed(MouseEvent arg0) {
        dragStart = new Point(arg0.getX(), arg0.getY());
        if(mouseIn)  setCursor(dragCursor);
    }

    public void mouseReleased(MouseEvent arg0) {
        setCursor(normalCursor);
    }

    public void mouseEntered(MouseEvent arg0) {
        mouseIn = true;

    }

    public void mouseExited(MouseEvent arg0) {
        mouseIn = false;
        setCursor(normalCursor);
    }

    public void mouseDragged(MouseEvent arg0) {
        if(mouseIn){
            setCursor(dragCursor);
            int xdiff = arg0.getX() - dragStart.x;
            int ydiff = arg0.getY() - dragStart.y;
            bottomLeft.move(bottomLeft.x-xdiff, bottomLeft.y+ydiff);
            dragStart = new Point(arg0.getX(), arg0.getY());
//            this.listener.setStatus("Bottom Left: ("+bottomLeft.x+", "+bottomLeft.y+")");
            this.repaint();
        }
    }

    public void mouseMoved(MouseEvent arg0) {

        Point real = getRealFromScreen(new Point(arg0.getX(), arg0.getY()));

        this.listener.updateLocation(real.x, real.y);
    }

    /**
     * @return the dimensions
     */
    public Dimension getDimensions() {
        return this.container.getSize();
    }


    public void componentResized(ComponentEvent arg0) {
//        this.footprintPanel.setBounds(0, 0, this.getDimensions().width, this.getDimensions().height);
        this.repaint();
    }

    public void componentMoved(ComponentEvent arg0) {
    }

    public void componentShown(ComponentEvent arg0) {
    }

    public void componentHidden(ComponentEvent arg0) {
    }


}
